package ipcards;

import ipcards.events.PlayerAction;

import java.util.*;
import java.awt.Point;

/**
A set of cards.
*/
public class CardSet extends HashSet<Card> {
	
	private HashMap<Integer,Card> idToCard = new HashMap<Integer,Card>();
	public LinkedList<Card> ZValueOrder = new LinkedList<Card>();
	
	
	public CardSet(Collection<Card> initial) {
		super();
		addAll(initial);
		for(Card c: initial){
			if(!(ZValueOrder.contains(c))){
				ZValueOrder.add(c);
			}
		}
	}
	
	public CardSet(Card initial) {
		super();
		add(initial);
		if(!(ZValueOrder.contains(initial))){
			ZValueOrder.add(initial);
		}
	}
	
	public CardSet() {
		super();
	}
	
	public boolean add(Card c) {
		
		idToCard.put(c.getID(), c);	// map id to card, for quick lookup
		if(!(ZValueOrder.contains(c))){
			ZValueOrder.add(c);
		}
		return super.add(c);
	}
	
	public void clear() {
		idToCard = new HashMap<Integer,Card>();
		ZValueOrder.clear();
		super.clear();
	}
	
	public int size() {
		return idToCard.size();
	}
	
	
	public boolean remove(Card c) {
		idToCard.remove(c.getID());
		ZValueOrder.remove(c);
		return super.remove(c);
	}
	
	public int[] getCardIDs() {
		Set<Integer> ids = idToCard.keySet();
		int[] arrint = new int[ids.size()];
		int i = 0;
		for (int id: ids) arrint[i++] = id;
		return arrint;
	}
	
	/**
	returns the card with the given id.  if there is no such card, returns null.
	*/
	public Card getCardFromID(int id) {
		return idToCard.get(id);
	}
	
	public Card getCardFromZ(int zvalue) {
		//ArrayList<Card> zDecList= (ArrayList)(getZDescendingList());
		if(zvalue < ZValueOrder.size()){
			return ZValueOrder.get(zvalue);
		}
		System.out.println("Z value " + zvalue + " is out of range for this list (which is of size " + ZValueOrder.size() + ")");
		return null;
	}
	
	/**
	Returns a copy of this set of cards, that is sorted in ascending order of Z coordinate.  This is provided for convenience, since often you will want iterate through cards from bottom to top, such as when rendering, or finding the top card.
	
	The List returned is only guaranteed to be in correct order at the time it was created.  If the underlying cards are changed, the List will probably no longer be in the correct order.  So the List returned by this method should be used immediately, and the method should be called again each subsequent time the List is needed, rather that saving and keeping the List.
	*/
	public LinkedList<Card> getZAscendingList() {
		return ZValueOrder;
	}
	
	/**
	The same as getZAscendingList(), but in reverse Z order.
	*/
	public LinkedList<Card> getZDescendingList() {
		LinkedList<Card> sortedlist = new LinkedList<Card>();
		for(int i = ZValueOrder.size()-1; i < 0; i--){
			sortedlist.add(ZValueOrder.get(i));
		}
		return sortedlist;
	}
	
	public void shuffle() {
		Set<Card> shuffledSet = new HashSet<Card>();
		
		ArrayList<Integer> zedvalues = new ArrayList<Integer>();
		ArrayList<Point> points = new ArrayList<Point>();
		int numCardsInGroup = 0;
		
		for(Card c: this) {
			zedvalues.add(ZValueOrder.indexOf(c));
			points.add(c.getLocation());
			numCardsInGroup++;
			shuffledSet.add(c);			
		}
		
		int[] newOrder = randomPermute(numCardsInGroup);
		
		int index = 0;
		
		for(Card c2: shuffledSet) {
			c2.setLocation(points.get(newOrder[index]));
			c2.setZ(zedvalues.get(newOrder[index]));
			ZValueOrder.set(newOrder[index],c2);
			index++;
		}
	}
	
	private int[] randomPermute(int max) {
		ArrayList<Integer> unused = new ArrayList<Integer>();
		for (int i = 0; i < max; i++) {
			unused.add(i);
		}
		
		Random r = new Random();
		int[] order = new int[max];
		for (int i = 0; i < max; i++) {
			int chosen = r.nextInt(unused.size());
			order[i] = unused.get(chosen);
			unused.remove(chosen);
		}
		
		return order;
	}
	
	
	/*public String toString() {
		
		String ret = "";
		for(int c: idToCard.keySet()) {
			ret += c + " ";
		}
System.out.println(ret.trim());		
		return ret.trim();
	}*/
	
	/*public String toString() {
		
		String ret = "";
		for(int c: idToCard.keySet()) {
			ret += c + " ";
		}
		ret += ":::";
		for(int i=0;i<ZValueOrder.size();i++){
			Card card = ZValueOrder.get(i);
			int c = card.getID();
			ret += c + " ";
		}
System.out.println(ret.trim());		
		return ret.trim();
	}*/
	public String toString() {
		
		String ret = "";
		
		for(int i=0;i<ZValueOrder.size();i++){
			Card card = ZValueOrder.get(i);
			int c = card.getID();
			ret += c + " ";
		}

		return ret.trim();
	}
	
// 	public Card remove(int cardID) {
// 		return null;
// 	}
// 	
// 	public Card[] remove(int[] cardIDs) {
// 		return null;
// 	}
	
	
	
}

